import type { Identifier, XYCoord } from 'dnd-core'
import type { FC } from 'react'
import { useRef } from 'react'
import { useDrag, useDrop } from 'react-dnd'
import styles from './index.module.less';
import { findCardByIndexs } from '../../helper';
import { ChangePosLineProps, currentDropBoxesProps } from '../container';
import { MenuId, useContextMenu } from 'react-contexify';
import { MENU_ID } from '../contexify';

export interface IStateRefProps { 
    addIndex?: number[]
    isLeft?: boolean
    isUp: boolean 
}

export const ItemTypes = {
    CARD: 'card',
}

// const style = {
//     cursor: 'move',
// }

export interface CardProps {
    containerRef: React.MutableRefObject<HTMLDivElement | null>
    // direction: string
    data: DragItem
    index: number
    indexs: number[]
    canDrop: Record<'current', boolean>
    moveCard: (dragIndexs: number[], hoverIndexs: number[], position: IStateRefProps) => void
    addCard: (dragItem: DragItem, dropItem: DragItem, position: IStateRefProps) => void
    hoverIndex: number
    setHoverIndex: (hoverIndex: number) => void
    setCanDrop: (can: boolean) => void
    selectIndex: number[]
    setSelectIndex: (selectIndex: number[]) => void
    setLine: React.Dispatch<React.SetStateAction<ChangePosLineProps>>
    containerRect: { left: number, top: number }
    componentLibs: Map<string, React.ComponentType<unknown>>,
    currentDropBoxes: React.MutableRefObject<currentDropBoxesProps>,
    children?: unknown
}

export interface DragItem {
    index: number
    indexs: number[]
    id: number
    tab: string
    type: string
    mode?: string
    name: string
    title: string
    pic: string
    width: string | number
    height: string | number
    left?: number
    top?: number
    data: Record<string, unknown>
    direction?: string
    zIndex?: number
    childrens: DragItem[]
}



export const Card: FC<CardProps> = ({
    // direction,
    data,
    index,
    indexs,
    moveCard,
    addCard,
    canDrop,
    setCanDrop,
    selectIndex,
    setSelectIndex,
    setLine,
    containerRect,
    componentLibs,
    currentDropBoxes,
    children,
}) => {
    const ref = useRef<HTMLDivElement>(null);
    const stateRef = useRef<IStateRefProps>({
        addIndex: [],
        isLeft: false,
        isUp: false,
    });

    const { show } = useContextMenu({
        id: MENU_ID,
      });
    
    function handleContextMenu(event){
        event.stopPropagation();
        console.log('handleContextMenu', data, indexs)
        show({
        event,
        props: {
            item: data,
            indexs
        }})
    }

    // console.log('Card',data)
    const [{ handlerId, isOver }, drop] = useDrop<
        DragItem,
        void,
        { handlerId: Identifier | null }
    >({

        accept: 'static',
        collect(monitor) {
            return {
                handlerId: monitor.getHandlerId(),
                didDrop: monitor.didDrop(),
                isOver: monitor.isOver(),
            }
        },
        drop(item: DragItem) {
            // 仅最深层级的drop容器hover生效,不允许向上冒泡
            if (currentDropBoxes.current.currentDropBox !== indexs.toString()) {
                setTimeout(() => {
                    currentDropBoxes.current.currentDropBox = ''
                }, 200)
                return
            }
            console.log('Card drop', canDrop.current, stateRef.current)
            if (!ref.current) return;
            if (!canDrop.current) return;
            setCanDrop(false);
            
            setLine({ show: false })
            
            const dragItem = JSON.parse(JSON.stringify(item))
            if (item.indexs === undefined) {
                console.log('【card】addCard',dragItem, data, stateRef.current.addIndex)
                addCard(dragItem, data, stateRef.current);
                // setSelectIndex(stateRef.current.addIndex as number[])
            } else {
                moveCard(item.indexs, indexs, stateRef.current)
            }
        },
        hover(item: DragItem, monitor) {
            
            console.log('currentDropBoxes.current.dropBoxes.get(currentDropBoxes.current.currentDropBox)',currentDropBoxes.current.dropBoxes, currentDropBoxes.current.currentDropBox,  indexs.toString())
            // 仅最深层级的drop容器hover生效,不允许向上冒泡
            if (currentDropBoxes.current.currentDropBox !== indexs.toString()) {
                return
            }

            // 处理悬浮组件
            if (item.type === 'fixed') {
                return;
            }

            // 处理静态组件
            setCanDrop(true)
            if (!ref.current) {
                return
            }
           
            // Determine mouse position
            const clientOffset = monitor.getClientOffset()
            const scrollTop = (document.querySelector('#dragger')?.scrollTop || 0 + (document.querySelector('#dragger-wrapper')?.scrollTop || 0))  || 0;
            const _hoverBoundingRect = ref.current?.getBoundingClientRect()
            console.log('_hoverBoundingRect', _hoverBoundingRect, item)
            const hoverBoundingRect = {
                top: _hoverBoundingRect.top + scrollTop,
                // bottom: _hoverBoundingRect.bottom + scrollTop,
                left: _hoverBoundingRect.left,
                height: _hoverBoundingRect.height,
                width: _hoverBoundingRect.width,
                // hoverMiddleY: _hoverBoundingRect.height/2,
                // hoverMiddleY: _hoverBoundingRect.height/2,
            }
            
            // 修正滚动偏移
            const clientOffsetY = (clientOffset as XYCoord).y + scrollTop;
            // 鼠标位置，在drop容器内向下偏移距离
            const hoverClientY = clientOffsetY - hoverBoundingRect.top
            // 鼠标位置，在drop容器内向右偏移距离
            const hoverClientX = (clientOffset as XYCoord).x - hoverBoundingRect.left;
            
            
            console.log('【当前容器排列方向:】',data.direction, data)
            // 水平排列
            if(data.direction === 'row') {
                // 移动到容器左半区域
                if (hoverClientX > 0 && hoverClientX < (hoverBoundingRect.width / 2)) {
                    stateRef.current.addIndex = indexs;
                    stateRef.current.isUp = true;
                    console.log('【hoverMiddleX】left',stateRef.current, indexs, hoverClientX, hoverBoundingRect.width)
                    setLine({
                        show: true,
                        direction: data.direction,
                        top: hoverBoundingRect.top - containerRect.top,
                        left: hoverBoundingRect.left - containerRect.left,
                        width: 2,
                        height: hoverBoundingRect.height,
                    })
                // 移动到容器右半区域
                } else if (hoverClientX >= (hoverBoundingRect.width / 2) && hoverClientX <= hoverBoundingRect.width) {
                    console.log('【hoverMiddleX】right', indexs)
                    stateRef.current.addIndex = indexs;
                    stateRef.current.isUp = false;
                    setLine({
                        show: true,
                        direction: data.direction,
                        top: hoverBoundingRect.top - containerRect.top,
                        left: hoverBoundingRect.left + hoverBoundingRect.width - containerRect.left,
                        width: 2,
                        height: hoverBoundingRect.height,
                    })
                } else {
                    setLine({ show: false })
                }
            // 默认竖直排列
            } else {
                // 移动到容器的上半区域
                if (hoverClientY >= 0 && hoverClientY < (hoverBoundingRect.height/2)) {
                    console.log('【hoverMiddleY】up', indexs)
                    stateRef.current.addIndex = indexs;
                    stateRef.current.isUp = true;
                    setLine({
                        show: true,
                        direction: data.direction,
                        top: hoverBoundingRect.top - containerRect.top,
                        left: hoverBoundingRect.left - containerRect.left,
                        width: hoverBoundingRect.width,
                        height: 2,
                    })
                // 移动到容器的下半区域
                } else if (hoverClientY <= hoverBoundingRect.height &&  hoverClientY >= (hoverBoundingRect.height/2)) {
                    console.log('【hoverMiddleY】down', indexs)
                    stateRef.current.addIndex = indexs;
                    stateRef.current.isUp = false;
                    setLine({
                        show: true,
                        direction: data.direction,
                        top: hoverBoundingRect.top + hoverBoundingRect.height - containerRect.top,
                        left: hoverBoundingRect.left - containerRect.left,
                        width: hoverBoundingRect.width,
                        height: 2,
                    })
                } else {
                    setLine({ show: false })
                }
            }
        },
    }, [stateRef, moveCard])

    const [{ isDragging }, drag] = useDrag({
        type: data.type,
        item: () => {
            return { ...data, index, indexs }
        },
        collect: (monitor) => ({
            isDragging: monitor.isDragging(),
        }),
    })

    // 解决嵌套组件hover事件会冒泡到上层组件，导致同时触发多个组件hover
    // 收集所有触发hover了的元素坐标
    if (isOver) {
        indexs.toString() && currentDropBoxes.current.dropBoxes.set(indexs.toString(), indexs.length);
    } else {
    // 离开时移除当前元素坐标
        indexs.toString() && currentDropBoxes.current.dropBoxes.delete(indexs.toString());
        currentDropBoxes.current.currentDropBox = ''
    }
    // 从所有坐标中，找到层级最深的坐标，即当前hover的坐标
    for(const key of currentDropBoxes.current.dropBoxes.keys()) {
        if (key.length >= currentDropBoxes.current.currentDropBox.length) {
            currentDropBoxes.current.currentDropBox = key;
        }
    }

    // console.log('currentDropBoxes.current', currentDropBoxes.current.dropBoxes, currentDropBoxes.current.currentDropBox)

    const opacity = isDragging ? 0.5 : 1
    drag(drop(ref))

    const View = componentLibs.get(data.name) as React.ComponentType<{ [x: string]: unknown }>
    if (!selectIndex) {
        console.error('selectIndex格式有误', selectIndex)
    }
    const positionStyle = data.type === 'fixed' ? { position: 'absolute', left: data.left + 'px', top: data.top + 'px', zIndex: data.zIndex } : {}
    const selectStyle = (selectIndex || []).join('-') === indexs.join('-') ? { outline: '#722ed1 solid 1px', outlineOffset: 0 } : {}
    

    if (!data.data.props) {
        console.error(`${data.title}的props未定义`)
        return;
    }
    
    const viewProps =Object.keys(data.data.props).reduce((pv: Record<string, unknown>, cv) => {
            pv[cv] = (data.data.props as Record<string, Record<'initialValue', unknown>>)[cv].initialValue;
            return pv;
    }, {})
    // 如果props存在宽高属性，则将拖拽容器的宽高透传过去
    if (data.width) viewProps.width = data.width;
    if (data.height) viewProps.height = data.height;

    console.log('viewProps', children, (children as unknown[])?.length < 1)

    // 弹性容器为空时显示占位文案
    if (data.name === 'FlexBox' && (children as unknown[])?.length < 1) {
        children = <div style={{width: '100%', height: viewProps.height as number || 200, color: '#ccc', fontSize: 20, textAlign: 'center', lineHeight: (viewProps.height as number || 200) +'px'}}>
            把组件拖拽到这里
        </div>
    }
    
    return (
        <div 
            className={`${styles.card} ${(data.mode === 'box') ? styles.flexBox: ''}`} 
            data-id={data.id} 
            data-index={indexs.join('-')} 
            ref={ref} 
            style={{ 
                opacity, 
                width: viewProps.width || data.width, 
                height: viewProps.height || data.height, 
                ...selectStyle,
                ...positionStyle, 
            } as React.CSSProperties} 
            data-handler-id={handlerId} 
            onClick={(e) => { console.log('setSelectIndex', indexs); setSelectIndex(indexs); e.stopPropagation() }}
            onContextMenu={handleContextMenu}
        >
            {View ? <View children={children} { ...viewProps} /> : data.name}
        </div>
    )
}
